package com.qiwenshare.file.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qiwenshare.common.anno.MyLog;
import com.qiwenshare.common.result.RestResult;
import com.qiwenshare.file.dingding.api.DingdingOldSdkApi;
import com.qiwenshare.file.dingding.constant.DingdingEventTypeConstants;
import com.qiwenshare.file.dingding.service.IDingdingSynService;
import com.qiwenshare.file.dingding.util.DingCallbackCrypto;
import com.qiwenshare.file.domain.dept.DeptBean;
import com.qiwenshare.file.domain.user.UserBean;
import com.qiwenshare.file.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/dingding/syn")
public class DingdingSynController {
    public static final Logger log = LoggerFactory.getLogger(DingdingSynController.class);

    @Value("${dingding.agent.agentName}")
    public String agentName;

    @Value("${dingding.agent.aesKey}")
    public String agentAesKey;

    @Value("${dingding.agent.aesToken}")
    public String agentAesToken;

    @Value("${dingding.agent.appKey}")
    public String agentAppKey;

    @Autowired
    public DingdingOldSdkApi dingdingOldSdkApi;

    @Autowired
    public IDingdingSynService dingdingSynService;

    // 部门同步接口（超级管理员权限）
    /**
     * 同步钉钉部门
     * @return
     */
    @RequestMapping("/synchronizeDept")
    @MyLog(module = "dingding", operation = "钉钉部门同步")
    public RestResult synchronizeDept() {
        try {
            List<DeptBean> DeptBeanList = new ArrayList<>();
            recursionGetDept(1L, DeptBeanList);
//            String str = "[{\"children\":[],\"ddDeptId\":545525628,\"ddParentId\":545550593,\"deptName\":\"北美B组\",\"params\":{}},{\"children\":[],\"ddDeptId\":545550593,\"ddParentId\":716854208,\"deptName\":\"北美运营部\",\"params\":{}},{\"children\":[],\"ddDeptId\":101313452,\"ddParentId\":1,\"deptName\":\"跨境电商运营中心\",\"params\":{}},{\"children\":[],\"ddDeptId\":545100864,\"ddParentId\":101313461,\"deptName\":\"北美A组\",\"params\":{}},{\"children\":[],\"ddDeptId\":545827076,\"ddParentId\":545583620,\"deptName\":\"欧洲运营部\",\"params\":{}},{\"children\":[],\"ddDeptId\":721661167,\"ddParentId\":101313452,\"deptName\":\"拼多多运营\",\"params\":{}},{\"children\":[],\"ddDeptId\":721490487,\"ddParentId\":101313452,\"deptName\":\"沃尔玛运营\",\"params\":{}},{\"children\":[],\"ddDeptId\":481296651,\"ddParentId\":1,\"deptName\":\"品牌运营中心\",\"params\":{}},{\"children\":[],\"ddDeptId\":545253737,\"ddParentId\":481296651,\"deptName\":\"品牌创意部\",\"params\":{}},{\"children\":[],\"ddDeptId\":545463623,\"ddParentId\":481296651,\"deptName\":\"品牌营销部\",\"params\":{}},{\"children\":[],\"ddDeptId\":545800075,\"ddParentId\":481296651,\"deptName\":\"品牌设计部\",\"params\":{}},{\"children\":[],\"ddDeptId\":486535033,\"ddParentId\":1,\"deptName\":\"供应链管理中心\",\"params\":{}},{\"children\":[],\"ddDeptId\":545031690,\"ddParentId\":486535033,\"deptName\":\"商品订单部\",\"params\":{}},{\"children\":[],\"ddDeptId\":545048760,\"ddParentId\":486535033,\"deptName\":\"品质管理部\",\"params\":{}},{\"children\":[],\"ddDeptId\":545105839,\"ddParentId\":486535033,\"deptName\":\"仓储物流部\",\"params\":{}},{\"children\":[],\"ddDeptId\":545210695,\"ddParentId\":486535033,\"deptName\":\"采购履行部\",\"params\":{}},{\"children\":[],\"ddDeptId\":545307795,\"ddParentId\":486535033,\"deptName\":\"商品开发部\",\"params\":{}},{\"children\":[],\"ddDeptId\":101313454,\"ddParentId\":1,\"deptName\":\"行政管理部\",\"params\":{}},\n" +
//                    "{\"children\":[],\"ddDeptId\":721215985,\"ddParentId\":101313454,\"deptName\":\"北美C组\",\"params\":{}},\n" +
//                    "{\"children\":[],\"ddDeptId\":101313461,\"ddParentId\":1,\"deptName\":\"战略管理部\",\"params\":{}},{\"children\":[],\"ddDeptId\":150578897,\"ddParentId\":1,\"deptName\":\"财务管理部\",\"params\":{}},{\"children\":[],\"ddDeptId\":716854208,\"ddParentId\":1,\"deptName\":\"IT信息部\",\"params\":{}},\n" +
//                    "{\"children\":[],\"ddDeptId\":545583620,\"ddParentId\":716854208,\"deptName\":\"亚马逊运营\",\"params\":{}}" +
//                    "]";
//            DeptBeanList = JSON.parseArray(str, DeptBean.class);
            log.info("【钉钉部门同步】部门列表：" + JSON.toJSONString(DeptBeanList));
            return RestResult.success().message(dingdingSynService.synchronizeDept(DeptBeanList));
        } catch (Exception e) {
            e.printStackTrace();
            return RestResult.fail().message("同步失败!" + e.getMessage());
        }
    }

    // 用户同步接口（超级管理员权限）
    @RequestMapping("/synchronizeUser")
    @MyLog(module = "dingding", operation = "钉钉用户同步")
    public RestResult synchronizeUser() {
        try {
            List<UserBean> users = new ArrayList<>();
            getUserByDeptId(users);
            log.info("【钉钉用户同步】用户列表：" + JSON.toJSONString(users));
            return RestResult.success().message(dingdingSynService.synchronizeUser(users));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 递归查询钉钉部门列表
     * @param pDeptId
     * @param DeptBeanList
     */
    public void recursionGetDept(Long pDeptId, List<DeptBean> DeptBeanList) {
        List<DingdingOldSdkApi.DeptSimpleInfo> deptListArr = dingdingOldSdkApi.getDepartmentListsub(pDeptId);
        if (deptListArr != null) {
            if (!deptListArr.isEmpty()) {
                // 先判断DeptBeanList中是否存在父列表
                    for (DingdingOldSdkApi.DeptSimpleInfo o : deptListArr) {
                        DeptBean dept = new DeptBean();
                        dept.setDdDeptId(o.getDeptId());
                        dept.setDdParentId(o.getParentId());
                        dept.setDeptName(o.getName());
                        DeptBeanList.add(dept);
                        recursionGetDept(o.getDeptId(), DeptBeanList);
                    }
            }
        }
    }

    public void getUserByDeptId(List<UserBean> users){
        List<DeptBean> DeptBeanList = new ArrayList<>();
        recursionGetDept(1L, DeptBeanList);
        Long size = 100L;
        for (DeptBean dept : DeptBeanList) {
            // 根据部门id查询用户列表
            Long cursor = 0L;
            Boolean hasMore = true;
            while(hasMore) {
                JSONObject userListByDeptid = dingdingOldSdkApi.getUserListByDeptid(dept.getDdDeptId(), cursor, size);
                if (userListByDeptid != null) {
                    hasMore = userListByDeptid.getBoolean("has_more");
                    cursor = userListByDeptid.getLong("next_cursor");
                    List<DingdingOldSdkApi.UserInfo> list = (List<DingdingOldSdkApi.UserInfo>) userListByDeptid.get("list");
                    for (DingdingOldSdkApi.UserInfo userInfo : list) {
                        log.info("user info:{}", JSON.toJSONString(userInfo));
                        UserBean user = new UserBean();
                        user.setDdUserId(userInfo.getUserid());
                        user.setUsername(StringUtils.isEmpty(userInfo.getMobile())?userInfo.getJobNumber():userInfo.getMobile());
                        user.setNickname(userInfo.getName());
                        // 将部门列表中第一个部门id赋值给主部门id
//                        user.setDdDeptId(dept.getDdDeptId());
                        if (userInfo.getDeptIdList() != null) {
                            user.setDdDeptId(userInfo.getDeptIdList().size()>1 && userInfo.getDeptIdList().get(0).equals(1L)? userInfo.getDeptIdList().get(1): userInfo.getDeptIdList().get(0));
                            // 用户表新增部门id列表字段逗号分隔
                            user.setDdDeptIds(String.join(",", userInfo.getDeptIdList().stream().map(String::valueOf).collect(Collectors.toList())));
                        }
                        user.setPassword(StringUtils.isEmpty(userInfo.getMobile())?userInfo.getJobNumber():userInfo.getMobile());
                        user.setEmail(userInfo.getEmail());
                        user.setTelephone(StringUtils.isEmpty(userInfo.getMobile())?userInfo.getJobNumber():userInfo.getMobile());
                        user.setSalt(StringUtils.isEmpty(userInfo.getMobile())?userInfo.getJobNumber():userInfo.getMobile());
                        users.add(user);
                    }
                }
            }
        }
    }

    @RequestMapping("/callBack")
    public Map<String, String> callBack(
            @RequestParam(value = "msg_signature", required = false) String msg_signature,
            @RequestParam(value = "timestamp", required = false) String timeStamp,
            @RequestParam(value = "nonce", required = false) String nonce,
            @RequestBody(required = false) JSONObject json) {
        log.info("【钉钉订阅事件通知接收】");
        try {
            // 1. 从http请求中获取加解密参数
            // 2. 使用加解密类型
            // Constant.OWNER_KEY 说明：
            // 1、开发者后台配置的订阅事件为应用级事件推送，此时OWNER_KEY为应用的APP_KEY。
            // 2、调用订阅事件接口订阅的事件为企业级事件推送，
            //      此时OWNER_KEY为：企业的appkey（企业内部应用）或SUITE_KEY（三方应用）
            DingCallbackCrypto callbackCrypto = new DingCallbackCrypto(agentAesToken, agentAesKey, agentAppKey);
            // 解密
            String encryptMsg = json.getString("encrypt");
            String decryptMsg = callbackCrypto.getDecryptMsg(msg_signature, timeStamp, nonce, encryptMsg);

            // 3. 反序列化回调事件json数据
            JSONObject eventJson = JSON.parseObject(decryptMsg);
            String eventType = eventJson.getString("EventType");

            // 4. 根据EventType分类处理
            if ("check_url".equals(eventType)) {
                log.info("测试回调url的正确性");
            } else if (DingdingEventTypeConstants.USER_ADD_ORG.equals(eventType)) {
                log.info("【钉钉订阅事件】：" + eventType + "事件");
                /** 处理用户添加事件：查询用户详情，关联部门 */
                JSONArray arr = eventJson.getJSONArray("UserId");
                List<String> userIds = arr.toJavaList(String.class);
                List<UserBean> addUsers = new ArrayList<>();
                userIds.forEach(v -> {
                    DingdingOldSdkApi.UserInfo userInfo = dingdingOldSdkApi.getUserDetailByUserid(v);
                    UserBean user = new UserBean();
                    user.setDdUserId(userInfo.getUserid());
                    user.setUsername(StringUtils.isEmpty(userInfo.getMobile())?userInfo.getJobNumber():userInfo.getMobile());
                    user.setNickname(userInfo.getName());
                    // 将部门列表中第一个部门id赋值给主部门id
//                        user.setDdDeptId(dept.getDdDeptId());
                    user.setDdDeptId(userInfo.getDeptIdList().get(0).equals(1L) && userInfo.getDeptIdList().size()>1? userInfo.getDeptIdList().get(1): userInfo.getDeptIdList().get(0));
                    // 用户表新增部门id列表字段逗号分隔
                    user.setDdDeptIds(String.join(",", userInfo.getDeptIdList().stream().map(String::valueOf).collect(Collectors.toList())));
                    user.setPassword(StringUtils.isEmpty(userInfo.getMobile())?userInfo.getJobNumber():userInfo.getMobile());
                    user.setEmail(userInfo.getEmail());
                    user.setTelephone(StringUtils.isEmpty(userInfo.getMobile())?userInfo.getJobNumber():userInfo.getMobile());
                    user.setSalt(StringUtils.isEmpty(userInfo.getMobile())?userInfo.getJobNumber():userInfo.getMobile());
                    addUsers.add(user);
                });
                dingdingSynService.userEventDeal(eventType, addUsers);
            } else if (DingdingEventTypeConstants.USER_MODIFY_ORG.equals(eventType)) {
                log.info("【钉钉订阅事件】：" + eventType + "事件");
                /** 用户修改：针对用户部门修改 */
                // 此处针对id中包含“-”的字符串使用 直接转JSON.parseArray();会出现结果错误
                JSONArray arr = eventJson.getJSONArray("UserId");
                List<String> userIds = arr.toJavaList(String.class);
                List<UserBean> modifyUsers = new ArrayList<>();
                userIds.forEach(v -> {
                    DingdingOldSdkApi.UserInfo userInfo = dingdingOldSdkApi.getUserDetailByUserid(v);
                    if (userInfo != null) {
                        UserBean user = new UserBean();
                        user.setDdUserId(userInfo.getUserid());
                        user.setNickname(userInfo.getName());
                        // 将部门列表中第一个部门id赋值给主部门id
                        user.setDdDeptId(userInfo.getDeptIdList().get(0).equals(1L) && userInfo.getDeptIdList().size()>1? userInfo.getDeptIdList().get(1): userInfo.getDeptIdList().get(0));
                        // 用户表新增部门id列表字段逗号分隔
                        user.setDdDeptIds(String.join(",", userInfo.getDeptIdList().stream().map(String::valueOf).collect(Collectors.toList())));
                        user.setEmail(userInfo.getEmail());
                        user.setTelephone(StringUtils.isEmpty(userInfo.getMobile())?userInfo.getJobNumber():userInfo.getMobile());
                        user.setSalt(StringUtils.isEmpty(userInfo.getMobile())?userInfo.getJobNumber():userInfo.getMobile());
                        modifyUsers.add(user);
                    }
                });
                dingdingSynService.userEventDeal(eventType, modifyUsers);
            } else if (DingdingEventTypeConstants.USER_LEAVE_ORG.equals(eventType)) {
                log.info("【钉钉订阅事件】：" + eventType + "事件");
                /** 用户离职：将用户状态改为1停用 */
                JSONArray arr = eventJson.getJSONArray("UserId");
                List<String> userIds = arr.toJavaList(String.class);
                List<UserBean> leaveUsers = new ArrayList<>();
                userIds.forEach(v -> {
                    UserBean user = new UserBean();
                    user.setDdUserId(v);
                    leaveUsers.add(user);
                });
                dingdingSynService.userEventDeal(eventType, leaveUsers);
            }  else if (DingdingEventTypeConstants.ORG_DEPT_CREATE.equals(eventType)) {
                log.info("【钉钉订阅事件】：" + eventType + "事件");
                /** 部门创建：查询部门详情 */
                JSONArray arr = eventJson.getJSONArray("DeptId");
                List<Long> deptIds = arr.toJavaList(Long.class);
                List<DeptBean> addDept = new ArrayList<>();
                deptIds.forEach(v -> {
                    DingdingOldSdkApi.DeptDetailInfo deptDetail = dingdingOldSdkApi.getDeptDetailById(v);
                    DeptBean DeptBean = new DeptBean();
                    DeptBean.setDeptName(deptDetail.getName());
                    DeptBean.setStatus("0");
                    DeptBean.setDelFlag("0");
                    DeptBean.setDdDeptId(deptDetail.getDeptId());
                    DeptBean.setDdParentId(deptDetail.getParentId());
                    addDept.add(DeptBean);
                });
                dingdingSynService.deptEventDeal(eventType, addDept);
            }  else if (DingdingEventTypeConstants.ORG_DEPT_MODIFY.equals(eventType)) {
                log.info("【钉钉订阅事件】：" + eventType + "事件");
                /** 部门修改：查询部门详情*/
                JSONArray arr = eventJson.getJSONArray("DeptId");
                List<Long> deptIds = arr.toJavaList(Long.class);
                List<DeptBean> editDept = new ArrayList<>();
                deptIds.forEach(v -> {
                    DingdingOldSdkApi.DeptDetailInfo deptDetail = dingdingOldSdkApi.getDeptDetailById(v);
                    DeptBean DeptBean = new DeptBean();
                    DeptBean.setDeptName(deptDetail.getName());
                    DeptBean.setDdDeptId(deptDetail.getDeptId());
                    DeptBean.setDdParentId(deptDetail.getParentId());
                    editDept.add(DeptBean);
                });
                dingdingSynService.deptEventDeal(eventType, editDept);
            }  else if (DingdingEventTypeConstants.ORG_DEPT_REMOVE.equals(eventType)) {
                log.info("【钉钉订阅事件】：" + eventType + "事件");
                /** 部门删除*/
                JSONArray arr = eventJson.getJSONArray("DeptId");
                List<Long> deptIds = arr.toJavaList(Long.class);
                List<DeptBean> removeDept = new ArrayList<>();
                deptIds.forEach(v -> {
                    DeptBean DeptBean = new DeptBean();
                    DeptBean.setDdDeptId(v);
                    removeDept.add(DeptBean);
                });
                dingdingSynService.deptEventDeal(eventType, removeDept);
            } else {
                // 添加其他已注册的
                log.info("【钉钉订阅事件】：" + eventType + "事件");
            }

            // 5. 返回success的加密数据
            Map<String, String> successMap = callbackCrypto.getEncryptedMap("success");
            log.info("【钉钉订阅事件通知接收成功返回】");
            return successMap;

        } catch (DingCallbackCrypto.DingTalkEncryptException e) {
            e.printStackTrace();
            log.error("【钉钉订阅事件解析异常】信息：" + e.getMessage());
        }
        return null;
    }
}